package jcron

import (
	"fmt"
	"gf-start-kit/plugins/job/model/job"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gcron"
	"github.com/gogf/gf/util/gconv"
	"github.com/golang/glog"
	"reflect"
	"runtime"
	"time"
)

type Entity struct {
	FuncName string
	Param    string
	Run      func(cronKey string) error
}

var taskList = garray.New()

func Add(task Entity) {
	if task.FuncName == "" {
		return
	}
	if task.Run == nil {
		return
	}
	if GetByName(task.FuncName) != nil {
		glog.Errorf("%s已经存在", task.FuncName)
		return
	}
	taskList.Append(task)
}
func Adds(tasks g.Slice) {
	for _, v := range tasks {
		item := v.(Entity)
		Add(item)
	}
}
func Dump() {
	for _, value := range Map() {
		m := gconv.Map(value)
		g.Log().Infof("-----------bindTaskFunc success fun:%s doName:%s-----------", m["Run"], m["FuncName"])
	}
	//g.Dump(Map())
}
func Map() g.Slice {
	s := g.Slice{}
	for _, value := range taskList.Slice() {
		m := gconv.Map(value)
		m["Run"] = GetFunName(m["Run"])
		s = append(s, m)
	}
	return s
}

//检查方法名是否存在
func GetByName(funcName string) *Entity {
	var result *Entity
	for _, item := range taskList.Slice() {
		task := item.(Entity)
		if task.FuncName == funcName {
			result = &task
			break
		}
	}
	return result
}
func HasFun(funcName string) bool {
	r := false
	for _, item := range taskList.Slice() {
		task := item.(Entity)
		if task.FuncName == funcName {
			r = true
			break
		}
	}
	return r
}

// Run 运行
func Run(job func(cronKey string) error, cronKey string) {
	from := time.Now().UnixNano()
	err := job(cronKey)
	to := time.Now().UnixNano()
	//jobName := runtime.FuncForPC(reflect.ValueOf(job).Pointer()).Name()
	jobName := GetFunName(job)
	if err != nil {
		g.Log().Errorf("执行定时器：%s,方法：%s error:%s %dms\n", cronKey, jobName, err.Error(), (to-from)/int64(time.Millisecond))
	} else {
		g.Log().Infof("执行定时器：%s,方法：%s success: %d ms\n", cronKey, jobName, (to-from)/int64(time.Millisecond))
	}
}
func GetFunName(fun interface{}) string {
	return runtime.FuncForPC(reflect.ValueOf(fun).Pointer()).Name()
}

//开始一个任务
func Start(e *job.Entity) error {
	f := GetByName(e.FunName)
	if f == nil {
		return gerror.New("当前task目录下没有绑定这个方法")
	}
	taskId := gconv.String(e.Id)
	if e.Times == 0 {
		fmt.Printf("Start %s, times is 0", taskId)
		return nil
	}
	var task *gcron.Entry
	var err error
	if e.Times <= -1 {
		task, err = gcron.Add(e.Expression, func() {
			Run(f.Run, taskId)
		}, taskId)

	}
	if e.Times == 1 {
		task, err = gcron.AddOnce(e.Expression, func() {
			Run(f.Run, taskId)
		}, taskId)

	}
	if e.Times > 1 {
		task, err = gcron.AddTimes(e.Expression, e.Times, func() {
			Run(f.Run, taskId)
		}, taskId)
	}
	if err != nil || task == nil {
		fmt.Printf("task is nil, err:%s", err)
		return nil
	}
	_, _ = job.Model.Data(g.Map{"status": 0}).Where(job.Columns.Id, e.Id).Update()
	gcron.Start(taskId)
	fmt.Println(fmt.Sprintf("Start %s", taskId))
	return nil
}

//结束一个任务
func Stop(e *job.Entity) error {
	f := GetByName(e.FunName)
	if f == nil {
		return gerror.New("当前task目录下没有绑定这个方法")
	}
	taskId := gconv.String(e.Id)
	if gcron.Search(taskId) != nil {
		fmt.Println(fmt.Sprintf("Stop %s", taskId))
		_, _ = job.Model.Data(g.Map{"status": 1}).Where(job.Columns.Id, e.Id).Update()
		gcron.Stop(taskId)
	}
	return nil
}
